// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.db2.ast.DB2Object;
// import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
// import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveInsert;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveInsertStatement;
// import com.alibaba.druid.sql.dialect.hive.ast.HiveMultiInsertStatement;
// import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
// import com.alibaba.druid.sql.dialect.hive.visitor.HiveASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
// import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement_ptr;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.odps.ast.OdpsCreateTableStatement;
// import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
// import com.alibaba.druid.sql.dialect.odps.visitor.OdpsASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.*;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
// import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement;
// import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitorAdapter;
// import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
// import com.alibaba.druid.util.FnvHash;
// import com.alibaba.druid.util.PGUtils;

// import java.util.ArrayList;
// import java.util.List;
#pragma once

#include "../../utils/common_ptr.h"
#include "SchemaResolveVisitor.h"
#include "../dialect/mysql/visitor/MySqlASTVisitorAdapter.h"
#include "../dialect/oracle/visitor/OracleASTVisitorAdapter.h"
#include "../dialect/sqlserver/visitor/SQLServerASTVisitorAdapter.h"

class SchemaResolveVisitorFactory_MySqlResolveVisitor
    : virtual public MySqlASTVisitorAdapter,
      virtual public SchemaResolveVisitor
{
public:
  SchemaRepository_ptr repository;
  int options;
  SchemaResolveVisitor_Context_ptr context;
  // SchemaResolveVisitorFactory *schemaResolveVisitorFactory;

  SchemaResolveVisitorFactory_MySqlResolveVisitor(SchemaRepository_ptr repository, int options);
  SHAREDOBJECT(SchemaResolveVisitorFactory_MySqlResolveVisitor);
  BOOL_ptr visit(MySqlRepeatStatement_ptr x);

  // BOOL_ptr visit(MySqlDeclareStatement x);

  // BOOL_ptr visit(MySqlCursorDeclareStatement x);

  BOOL_ptr visit(MysqlForeignKey_ptr x);

  BOOL_ptr visit(MySqlSelectQueryBlock_ptr x);

  bool visit(SQLSelectItem_ptr x);

  BOOL_ptr visit(MySqlCreateTableStatement_ptr x);

  BOOL_ptr visit(MySqlUpdateStatement_ptr x);

  // BOOL_ptr visit(MySqlDeleteStatement x);

  BOOL_ptr visit(MySqlInsertStatement_ptr x);

  // @Override
  BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option);

  int getOptions();

  // @Override
  SchemaResolveVisitor_Context_ptr getContext();

  SchemaResolveVisitor_Context_ptr createContext(SQLObject_ptr object);

  // @Override
  void popContext();

  SchemaRepository_ptr getRepository();

  bool visit(SQLForeignKeyImpl_ptr x) { return true; }
  void SendVisit(SQLForeignKeyImpl_ptr x) {}
};

// class SchemaResolveVisitorFactory_DB2ResolveVisitor : public DB2ASTVisitorAdapter, virtual public SchemaResolveVisitor
// {
//   public:
//   SchemaRepository_ptr repository;
//   int options;
//   SchemaResolveVisitor_Context_ptr context;

//   DB2ResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this.repository = repository;
//     this.options = options;
//   }

//   BOOL_ptr visit(DB2SelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x.getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(SQLIdentifierExpr_ptr x)
//   {
//     long hash64 = x.hashCode64();
//     if (hash64 == FnvHash.Constants.CURRENT_DATE || hash64 == DB2Object.Constants.CURRENT_TIME)
//     {
//       return BOOL::FALSE;
//     }

//     resolveIdent(this, x);
//     return BOOL::TRUE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this.context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != null)
//     {
//       context = context.parent;
//     }
//   }

//   // @Override
//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

class SchemaResolveVisitorFactory_OracleResolveVisitor 
: virtual public OracleASTVisitorAdapter, 
virtual public SchemaResolveVisitor
{
public:
  SchemaRepository_ptr repository;
  int options;
  SchemaResolveVisitor_Context_ptr context;
  // SchemaResolveVisitorFactory *schemaResolveVisitorFactory;

  SchemaResolveVisitorFactory_OracleResolveVisitor(SchemaRepository_ptr repository, int options);
  SHAREDOBJECT(SchemaResolveVisitorFactory_OracleResolveVisitor);

  // BOOL_ptr visit(OracleCreatePackageStatement x);

  // BOOL_ptr visit(OracleForStatement x);

  // BOOL_ptr visit(OracleForeignKey x);

  // BOOL_ptr visit(OracleSelectTableReference x);

  // BOOL_ptr visit(OracleSelectQueryBlock x);

  bool visit(SQLSelectItem_ptr x);

  bool visit(SQLIdentifierExpr_ptr x);

  // BOOL_ptr visit(OracleCreateTableStatement x);

  // BOOL_ptr visit(OracleUpdateStatement x);

  // BOOL_ptr visit(OracleDeleteStatement x);

  // BOOL_ptr visit(OracleMultiInsertStatement x);

  // BOOL_ptr visit(OracleMultiInsertStatement.InsertIntoClause x);

  // BOOL_ptr visit(OracleInsertStatement x);

  // @Override
  BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option);

  int getOptions();

  // @Override
  SchemaResolveVisitor_Context_ptr getContext();

  SchemaResolveVisitor_Context_ptr createContext(SQLObject_ptr object);

  // @Override
  void popContext();

  SchemaRepository_ptr getRepository();

  bool visit(SQLForeignKeyImpl_ptr x) { return true; }
  void SendVisit(SQLForeignKeyImpl_ptr x) {}
};

// class SchemaResolveVisitorFactory_OdpsResolveVisitor : public OdpsASTVisitorAdapter, virtual public SchemaResolveVisitor
// {
//   public:
//   int options;
//   SchemaRepository_ptr repository;
//   SchemaResolveVisitor_Context_ptr context;

//   OdpsResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this.repository = repository;
//     this.options = options;
//   }

//   BOOL_ptr visit(OdpsSelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x.getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(OdpsCreateTableStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsert x)
//   {
//     SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//     SQLExprTableSource_ptr tableSource = x.getTableSource();
//     if (tableSource != null)
//     {
//       ctx.setTableSource(x.getTableSource());
//       visit(tableSource);
//     }

//     List<SQLAssignItem> partitions = x.getPartitions();
//     if (partitions != null)
//     {
//       for (SQLAssignItem item : partitions)
//       {
//         item.accept(this);
//       }
//     }

//     SQLSelect select = x.getQuery();
//     if (select != null)
//     {
//       visit(select);
//     }

//     popContext();
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsertStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this.context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != null)
//     {
//       context = context.parent;
//     }
//   }

//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

// class SchemaResolveVisitorFactory_HiveResolveVisitor : public HiveASTVisitorAdapter, virtual public SchemaResolveVisitor
// {
//   public:
//   int options;
//   SchemaRepository_ptr repository;
//   SchemaResolveVisitor_Context_ptr context;

//   HiveResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this.repository = repository;
//     this.options = options;
//   }

//   BOOL_ptr visit(OdpsSelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x.getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(HiveCreateTableStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsert x)
//   {
//     SchemaResolveVisitor_Context_ptr ctx = createContext(x);

//     SQLExprTableSource_ptr tableSource = x.getTableSource();
//     if (tableSource != null)
//     {
//       ctx.setTableSource(x.getTableSource());
//       visit(tableSource);
//     }

//     List<SQLAssignItem> partitions = x.getPartitions();
//     if (partitions != null)
//     {
//       for (SQLAssignItem item : partitions)
//       {
//         item.accept(this);
//       }
//     }

//     SQLSelect select = x.getQuery();
//     if (select != null)
//     {
//       visit(select);
//     }

//     popContext();
//     return BOOL::FALSE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this.context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != null)
//     {
//       context = context.parent;
//     }
//   }

//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

// class SchemaResolveVisitorFactory_PGResolveVisitor : public PGASTVisitorAdapter, virtual public SchemaResolveVisitor
// {
//   public:
//   int options;
//   SchemaRepository_ptr repository;
//   SchemaResolveVisitor_Context_ptr context;

//   PGResolveVisitor(SchemaRepository_ptr repository, int options)
//   {
//     this.repository = repository;
//     this.options = options;
//   }

//   BOOL_ptr visit(PGSelectQueryBlock x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGFunctionTableSource x)
//   {
//     for (SQLParameter_ptr parameter : x.getParameters())
//     {
//       SQLName name = parameter.getName();
//       if (name instanceof SQLIdentifierExpr_ptr)
//       {
//         SQLIdentifierExpr_ptr identName = (SQLIdentifierExpr_ptr)name;
//         identName.setResolvedTableSource(x);
//       }
//     }

//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectItem x)
//   {
//     SQLExpr_ptr expr = x.getExpr();
//     if (expr instanceof SQLIdentifierExpr_ptr)
//     {
//       resolveIdent(this, (SQLIdentifierExpr_ptr)expr);
//       return BOOL::FALSE;
//     }

//     if (expr instanceof SQLPropertyExpr)
//     {
//       resolve(this, (SQLPropertyExpr)expr);
//       return BOOL::FALSE;
//     }

//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(SQLIdentifierExpr_ptr x)
//   {
//     if (PGUtils.isPseudoColumn(x.nameHashCode64()))
//     {
//       return BOOL::FALSE;
//     }

//     resolveIdent(this, x);
//     return BOOL::TRUE;
//   }

//   BOOL_ptr visit(PGUpdateStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGDeleteStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGSelectStatement x)
//   {
//     createContext(x);
//     visit(x.getSelect());
//     popContext();
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(PGInsertStatement x)
//   {
//     resolve(this, x);
//     return BOOL::FALSE;
//   }

//   // @Override
//   BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option)
//   {
//     return (options & option.mask) != 0;
//   }

//   int getOptions()
//   {
//     return options;
//   }

//   // @Override
//   SchemaResolveVisitor_Context_ptr getContext()
//   {
//     return context;
//   }

//   SchemaResolveVisitor_Context_ptr createContext(SQLObject object)
//   {
//     return this.context = new SchemaResolveVisitor_Context_ptr(object, context);
//   }

//   // @Override
//   void popContext()
//   {
//     if (context != null)
//     {
//       context = context.parent;
//     }
//   }

//   SchemaRepository_ptr getRepository()
//   {
//     return repository;
//   }
// };

class SchemaResolveVisitorFactory_SQLServerResolveVisitor
 : virtual public SQLServerASTVisitorAdapter, 
 virtual public SchemaResolveVisitor
{
public:
  int options;
  SchemaRepository_ptr repository;
  SchemaResolveVisitor_Context_ptr context;
  // SchemaResolveVisitorFactory *schemaResolveVisitorFactory;

  SchemaResolveVisitorFactory_SQLServerResolveVisitor(SchemaRepository_ptr repository, int options);
  SHAREDOBJECT(SchemaResolveVisitorFactory_SQLServerResolveVisitor);
  BOOL_ptr visit(SQLServerSelectQueryBlock_ptr x);

  bool visit(SQLSelectItem_ptr x);

  // BOOL_ptr visit(SQLServerUpdateStatement_ptr x);

  BOOL_ptr visit(SQLServerInsertStatement_ptr x);

  // @Override
  BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option);

  int getOptions();

  // @Override
  SchemaResolveVisitor_Context_ptr getContext();

  SchemaResolveVisitor_Context_ptr createContext(SQLObject_ptr object);

  // @Override
  void popContext();

  SchemaRepository_ptr getRepository();

  bool visit(SQLForeignKeyImpl_ptr x) { return true; }
  void SendVisit(SQLForeignKeyImpl_ptr x) {}
};

class SchemaResolveVisitorFactory_SQLResolveVisitor 
: virtual public SQLASTVisitorAdapter, 
virtual public SchemaResolveVisitor
{
public:
  int options;
  SchemaRepository_ptr repository;
  SchemaResolveVisitor_Context_ptr context;
  // SchemaResolveVisitorFactory *schemaResolveVisitorFactory;

  SchemaResolveVisitorFactory_SQLResolveVisitor(SchemaRepository_ptr repository, int options);
  SHAREDOBJECT(SchemaResolveVisitorFactory_SQLResolveVisitor);
  bool visit(SQLSelectItem_ptr x);

  // @Override
  BOOL_ptr isEnabled(SchemaResolveVisitor_Option_ptr option);

  int getOptions();

  // @Override
  SchemaResolveVisitor_Context_ptr getContext();

  SchemaResolveVisitor_Context_ptr createContext(SQLObject_ptr object);

  // @Override
  void popContext();

  SchemaRepository_ptr getRepository();

  bool visit(SQLForeignKeyImpl_ptr x) { return true; }
  void SendVisit(SQLForeignKeyImpl_ptr x) {}
};

class SchemaResolveVisitorFactory
{
public:
  SHAREDOBJECT(SchemaResolveVisitorFactory);
  static void resolve(SchemaResolveVisitor_ptr visitor, SQLCreateTableStatement_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLUpdateStatement_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLDeleteStatement_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLInsertStatement_ptr x);

  static void resolveIdent(SchemaResolveVisitor_ptr visitor, SQLIdentifierExpr_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLPropertyExpr_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLBinaryOpExpr_ptr x);

  static SQLTableSource_ptr unwrapAlias(SchemaResolveVisitor_Context_ptr ctx, SQLTableSource_ptr tableSource, long identHash);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLSelectQueryBlock_ptr x);

  static void extractColumns(SchemaResolveVisitor_ptr visitor,
                             SQLTableSource_ptr from,
                             string_ptr ownerName,
                             SQLSelectItem_list_ptr columns);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLAllColumnExpr_ptr x);
  static void resolve(SchemaResolveVisitor_ptr v, SQLMethodInvokeExpr_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLSelect_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLWithSubqueryClause_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLExprTableSource_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLAlterTableStatement_ptr x);
  // static void resolve(SchemaResolveVisitor_ptr visitor, SQLMergeStatement_ptr x);

  // static void resolve(SchemaResolveVisitor_ptr visitor, SQLCreateFunctionStatement_ptr x);

  // static void resolve(SchemaResolveVisitor_ptr visitor, SQLCreateProcedureStatement_ptr x);

  // static BOOL_ptr resolve(SchemaResolveVisitor_ptr visitor, SQLIfStatement_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLBlockStatement_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLParameter_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLDeclareItem_ptr x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLOver_ptr x);

  static BOOL_ptr checkParameter(SchemaResolveVisitor_ptr visitor, SQLIdentifierExpr_ptr x);

  // static void resolve(SchemaResolveVisitor_ptr visitor, SQLReplaceStatement x);

  // static void resolve(SchemaResolveVisitor_ptr visitor, SQLFetchStatement x);

  static void resolve(SchemaResolveVisitor_ptr visitor, SQLForeignKeyConstraint_ptr x);

  // static void resolve(SchemaResolveVisitor_ptr visitor, SQLCreateViewStatement x);

  // for performance
  static void resolveExpr(SchemaResolveVisitor_ptr visitor, SQLExpr_ptr x);

  static void resolveUnion(SchemaResolveVisitor_ptr visitor, SQLUnionQuery_ptr x);
};
